package com.sojson.util.file;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.MemoryCacheImageInputStream;

import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import com.sojson.constant.Constant;
import com.sojson.constant.ConstantByMap;
import com.sojson.util.MavenUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.file.bean.FileBean;
import com.sojson.util.file.enums.EFileType;
import com.sojson.util.file.interfaces.FileSystemInterface;
import com.sojson.util.file.interfaces.impl.FastDfsUtilImpl;
import com.sojson.util.file.interfaces.impl.FileUtilImpl;
import com.sojson.util.file.interfaces.impl.OssUtilImpl;
import com.sojson.util.id.GUIDUtil;
import com.sojson.util.text.Convert;
import com.sojson.util.url.UrlUtil;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 文件工具类
 * 
 * @author liu
 * @Date 2020-06-15 14:45:33
 * @Description
 *
 */
@Slf4j
public class FileUtil extends org.apache.commons.io.FileUtils {

    /** file: */
    public static final String FILE_ = "file:";
    /** 远程文件存储系统存放文件的路径 */
    public static final String LONG_FILE_SYSTEM_BUCKET_NAME_BASE =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.fileSystem.long.bucketName.base"), "");
    /** 本地文件存储系统存放文件的路径 */
    public static final String THIS_LOCALITY_FILE_SYSTEM_BUCKET_NAME_BASE =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.fileSystem.thisLocality.bucketName.base"), "");
    /** 本地目录存放文件的基础路径 */
    public static final String THIS_LOCALITY_DIRECTORY_BUCKET_NAME_BASE =
        ConstantByMap.LOG_PATH_FILE_SYSTEM_THIS_DIRECTORY_BUCKET_NAME_BASE;
    /** 本地目录存放文件的访问路径 */
    public static final String THIS_LOCALITY_DIRECTORY_BUCKET_NAME_BASE_URL =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.controller.url.thisDirectory.bucketName.base"), "");
    private static final FileSystemInterface LONG_FILE_SYSTEM = OssUtilImpl.getInstances();
    private static final FileSystemInterface THIS_LOCALITY_FILE_SYSTEM = FastDfsUtilImpl.getInstances();
    private static final FileSystemInterface THIS_LOCALITY_DIRECTORY = FileUtilImpl.getInstances();

    /**
     * 创建需要的文件结构
     * 
     * @param properties 存储了目录键值对的Properties集合，可通过读取properties文件获取properties对象
     */
    public static void createFileStructure() {
        Collection<Object> values = Constant.LOG_PATH.values();
        for (Object value : values) {
            makeDirectoryByPathname((String)value);
            log.info("正在创建" + value + "目录");
        }
    }

    /**
     * 判断文件是否存在，不存在则创建
     * 
     * @param file File文件对象
     * @throws IOException
     */
    public static void createNewFileByFile(File file) throws IOException {
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    /**
     * 判断文件是否存在，不存在则创建
     * 
     * @param filePath 文件路径
     * @throws IOException
     */
    public static void createNewFileByPathname(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    /**
     * 判断目录是否存在，不存在则创建
     * 
     * @param file File文件对象
     */
    public static void makeDirectoryByFile(File file) {
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 判断目录是否存在，不存在则创建
     * 
     * @param filePath 文件路径
     */
    public static void makeDirectoryByPathname(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 判断文件是否存在，存在则删除<BR/>
     * 因为File无法删除非空目录，所以需要先递归所有子文件<BR/>
     * 
     * @param file File文件对象
     */
    public static void deleteFileByFile(File file) {
        // 判断文件是否存在
        if (file.exists()) {
            // 判断是文件还是目录
            if (file.isFile()) {
                // 是文件就删除
                file.delete();
            } else {
                // 是目录就递归调用此方法
                // 获取目录下的所有文件
                File[] listFiles = file.listFiles();
                for (File f : listFiles) {
                    deleteFileByFile(f);
                }
            }
        }
    }

    /**
     * 判断文件是否存在，存在则删除<BR/>
     * 因为File无法删除非空目录，所以需要先递归所有子文件<BR/>
     * 
     * @param filePath 文件路径
     */
    public static void deleteFileByPathname(String filePath) {
        File file = new File(filePath);
        // 判断文件是否存在
        if (file.exists()) {
            // 判断是文件还是目录
            if (file.isFile()) {
                // 是文件就删除
                file.delete();
            } else {
                // 是目录就递归调用此方法
                // 获取目录下的所有文件
                File[] listFiles = file.listFiles();
                for (File f : listFiles) {
                    deleteFileByFile(f);
                }
            }
        }
    }

    /**
    * 获取文件名称
    *
    * @param filePath 文件路径
    * @return
    */
    public static String getFileName(String filePath) {
        String generateGuid = GUIDUtil.generateGuid();
        int lastIndexOf = filePath.lastIndexOf(".");
        if (lastIndexOf > 0) {
            return new StringBuilder(generateGuid).append(".").append(filePath.substring(lastIndexOf + 1)).toString();
        }
        return generateGuid;
    }

    /**
     * 获取文件后缀
     * 
     * @param fileName 文件名
     * @return
     * @throws IOException 
     */
    public static String getFileSuffix(String fileName) throws IOException {
        int lastIndexOf = fileName.lastIndexOf(".");
        if (lastIndexOf > 0) {
            return fileName.substring(lastIndexOf + 1);
        }
        return "";
    }

    /**
     * 获取文件后缀
     * 
     * @param file
     * @return
     * @throws IOException 
     */
    public static EFileType getFileType(File file) throws IOException {
        EFileType fileType = null;
        InputStream in = null;
        try {
            in = IoUtil.toStream(file);
            fileType = getFileType(in);
        } finally {
            FileUtil.closeStream(in);
        }
        return fileType;
    }

    /**
     * 获取文件后缀
     * 
     * @param inputStream
     * @return
     * @throws IOException 
     */
    public static EFileType getFileType(InputStream inputStream) throws IOException {
        String readHex = IoUtil.readHex(inputStream, 28, false);
        return checkType(readHex);
    }

    /**
     * 获取文件后缀
     * 
     * @param bytes
     * @return
     * @throws IOException 
     */
    public static EFileType getFileType(byte[] bytes) throws IOException {
        byte[] bt = getFileHead(bytes);
        return getFileTypeDesc(bt);
    }

    /**
     * 获取文件后缀
     * 
     * @param bt
     * @return
     * @throws IOException 
     */
    private static EFileType getFileTypeDesc(byte[] bt) throws IOException {
        String encodeHexStr = HexUtil.encodeHexStr(bt, false);
        return checkType(encodeHexStr);
    }

    /**
     * 获取文件后缀
     * 
     * @param bytes
     * @return
     * @throws IOException 
     */
    private static byte[] getFileHead(byte[] bytes) throws IOException {
        int len = bytes.length;
        if (len > 28) {
            len = 28;
        }

        byte[] bt = new byte[len];
        for (int i = 0; i < len; i++) {
            bt[i] = bytes[i];
        }
        return bt;
    }

    /**
     * 通过代码获取文件后缀
     * 
     * @param code
     * @return
     */
    private static EFileType checkType(String code) {
        EFileType fileType = null;
        EFileType[] values = EFileType.values();
        for (EFileType eFileType : values) {
            if (StrUtil.startWithIgnoreCase(code, eFileType.getCode())) {
                fileType = eFileType;
                break;
            }
        }

        if (fileType == EFileType.ZIP) {
            if (StrUtil.startWithIgnoreCase(code, EFileType.XLSX_DOCX.getCode())) {
                fileType = EFileType.XLSX_DOCX;
            } else if (StrUtil.startWithIgnoreCase(code, EFileType.JAR.getCode())) {
                fileType = EFileType.JAR;
            } else if (StrUtil.startWithIgnoreCase(code, EFileType.JAR_2.getCode())) {
                fileType = EFileType.JAR_2;
            }
        } else if (fileType == EFileType.XLS) {

        }

        if (fileType == null) {
            return EFileType.NULL;
        }

        return fileType;
    }

    /**
     * 从ClasspathResources目录下获取输入流
     * 
     * @param filePath
     * @return
     * @throws IOException 
     */
    public static InputStream getClassPathInputStream(String filePath) throws IOException {
        // 去掉开头的斜线
        filePath = removeStartXVerify(filePath);

        InputStream inputStream = null;
        // 获取文件
        ClassPathResource classPathResource = new ClassPathResource(filePath);
        if (classPathResource.exists()) {
            inputStream = classPathResource.getInputStream();
        }
        return inputStream;
    }

    /**
     * 从项目根目录下获取输入流
     * 
     * @param filePath
     * @return
     * @throws IOException 
     */
    public static InputStream getFileInputStream(String filePath) throws IOException {
        // 格式化路径
        filePath = formatUrl(filePath);
        // 添加开头的斜线
        filePath = addStartXVerify(filePath);

        InputStream inputStream = null;
        if (MavenUtil.fileIsJar()) {
            // jar包
            filePath = removeStartX(filePath);
            // 获取JarFile
            JarFile jarFile = MavenUtil.getJarFile();
            // 获取文件
            JarEntry jarEntry = jarFile.getJarEntry(filePath);
            if (isNotBlankObject(jarEntry)) {
                // 返回输入流
                inputStream = jarFile.getInputStream(jarEntry);
            }
        } else if (MavenUtil.fileIsWar()) {
            // war包
            File file = new File(MavenUtil.WAR_FILE_PATH + filePath);
            return new FileInputStream(file);
        } else {
            // 此为开发环境
            File file = new File(MavenUtil.PROJECT_PATH + filePath);
            return new FileInputStream(file);
        }
        return inputStream;
    }

    /**
     * 获取文件后缀
     * 
     * @param filePath 文件路径
     * @return
     * @throws IOException 
     */
    public static String getFileSuffixByPath(String filePath) throws IOException {
        filePath = filePath.replace("\\", "/");
        int xieLastIndexOf = filePath.lastIndexOf("/");
        int dianLastIndexOf = filePath.lastIndexOf(".");
        if (dianLastIndexOf < 0 || dianLastIndexOf < xieLastIndexOf) {
            return "";
        }
        return filePath.substring(dianLastIndexOf + 1);
    }

    /**
     * 将File转为MultipartFile
     * 
     * @param file
     * @return
     * @throws IOException 
     */
    public static MultipartFile fileToMultipartFile(File file) throws IOException {
        String name = file.getName();
        return new MockMultipartFile(name, name, ContentType.APPLICATION_OCTET_STREAM.toString(),
            new FileInputStream(file));
    }

    /**
     * 获取文件信息
     * 
     * @param filePath 文件路径
     * @return
     * @throws IOException 
     */
    public static FileBean getFileMessage(String filePath) throws IOException {
        String suffix = null;
        long size = 0;

        FileInputStream fileInputStream = null;
        File file = null;

        String d = ".";
        try {
            if (filePath.lastIndexOf(d) > 0) {
                suffix = filePath.substring(filePath.lastIndexOf(".") + 1);
            }
            file = new File(filePath);
            fileInputStream = new FileInputStream(file);
            size = fileInputStream.available();
        } finally {
            closeStream(fileInputStream);
        }
        return new FileBean(file.getName(), suffix, size);
    }

    /**
     * 获取图片文件信息
     * 
     * @param filePath 文件路径
     * @return
     * @throws IOException 
     */
    public static FileBean getImageFileMessage(String filePath) throws IOException {
        FileBean fileBean = new FileBean();

        File file = new File(filePath);
        fileBean.setName(file.getName());
        FileInputStream fileInputStream = new FileInputStream(file);
        fileBean.setSize(fileInputStream.available());

        MemoryCacheImageInputStream memoryCacheImageInputStream = new MemoryCacheImageInputStream(fileInputStream);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(memoryCacheImageInputStream);
        try {
            if (readers.hasNext()) {
                ImageReader next = readers.next();
                next.setInput(memoryCacheImageInputStream);
                fileBean.setSuffix(next.getFormatName());
                fileBean.setWidth(next.getWidth(0));
                fileBean.setHeight(next.getHeight(0));
            }
        } finally {
            if (StringUtil.isNotBlankObject(memoryCacheImageInputStream)) {
                memoryCacheImageInputStream.close();
            }
            closeStream(fileInputStream);
        }
        return fileBean;
    }

    /**
     * 获取图片文件信息
     * 
     * @param bytes
     * @return
     * @throws IOException
     */
    public static FileBean getImageFileMessage(byte[] bytes) throws IOException {
        FileBean fileBean = new FileBean();

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        fileBean.setSize(byteArrayInputStream.available());

        MemoryCacheImageInputStream memoryCacheImageInputStream = new MemoryCacheImageInputStream(byteArrayInputStream);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(memoryCacheImageInputStream);
        try {
            if (readers.hasNext()) {
                ImageReader next = readers.next();
                next.setInput(memoryCacheImageInputStream);
                fileBean.setSuffix(next.getFormatName());
                fileBean.setWidth(next.getWidth(0));
                fileBean.setHeight(next.getHeight(0));
            }
        } finally {
            if (StringUtil.isNotBlankObject(memoryCacheImageInputStream)) {
                memoryCacheImageInputStream.close();
            }
            closeStream(byteArrayInputStream);
        }
        return fileBean;
    }

    /**
     * 获取图片文件信息
     * 
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static FileBean getImageFileMessage(InputStream inputStream) throws IOException {
        FileBean fileBean = new FileBean();

        fileBean.setSize(inputStream.available());

        MemoryCacheImageInputStream memoryCacheImageInputStream = new MemoryCacheImageInputStream(inputStream);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(memoryCacheImageInputStream);
        try {
            if (readers.hasNext()) {
                ImageReader next = readers.next();
                next.setInput(memoryCacheImageInputStream);
                fileBean.setSuffix(next.getFormatName());
                fileBean.setWidth(next.getWidth(0));
                fileBean.setHeight(next.getHeight(0));
            }
        } finally {
            if (StringUtil.isNotBlankObject(memoryCacheImageInputStream)) {
                memoryCacheImageInputStream.close();
            }
        }
        return fileBean;
    }

    /**
     * 将InputStream转为byte[]
     * 
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] inputStreamToByte(InputStream inputStream) throws IOException {
        return IOUtils.toByteArray(inputStream);
    }

    /**
     * 将InputStream转为BufferedImage
     * 
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static BufferedImage inputStreamToBufferedImage(InputStream inputStream) throws IOException {
        return ImageIO.read(inputStream);
    }

    /**
     * 将byte[]转为BufferedImage
     * 
     * @param bytes
     * @return
     * @throws IOException
     */
    public static BufferedImage byteToBufferedImage(byte[] bytes) throws IOException {
        return ImageIO.read(byteToInputStream(bytes));
    }

    /**
     * 将byte[]转为InputStream
     * 
     * @param bytes
     * @return
     * @throws IOException
     */
    public static InputStream byteToInputStream(byte[] bytes) throws IOException {
        return new ByteArrayInputStream(bytes);
    }

    /**
     * 将BufferedImage转为InputStream
     * 
     * @param bufferedImage
     * @return
     * @throws IOException
     */
    public static InputStream bufferedImageToInputStream(BufferedImage bufferedImage, String suffix)
        throws IOException {
        return new ByteArrayInputStream(bufferedImageToByte(bufferedImage, suffix));
    }

    /**
     * 将BufferedImage转为byte[]
     * 
     * @param bufferedImage
     * @return
     * @throws IOException
     */
    public static byte[] bufferedImageToByte(BufferedImage bufferedImage, String suffix) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = null;
        byte[] byteArray = null;

        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, suffix, byteArrayOutputStream);
            byteArray = byteArrayOutputStream.toByteArray();
        } finally {
            FileUtil.closeStream(byteArrayOutputStream);
        }

        return byteArray;
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param inputStream
     * @param outputStream
     * @throws IOException
     */
    public static void write(InputStream inputStream, OutputStream outputStream) throws IOException {
        IOUtils.copy(inputStream, outputStream);
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param bytes
     * @param outputStream
     * @throws IOException
     */
    public static void write(byte[] bytes, OutputStream outputStream) throws IOException {
        IOUtils.write(bytes, outputStream);
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param bufferedImage
     * @param outputStream
     * @throws IOException
     */
    public static void write(BufferedImage bufferedImage, OutputStream outputStream) throws IOException {
        write(bufferedImage, outputStream, Constant.GENERATE_IMG_SUFFIX);
    }

    /**
     * 将输入流内容放到输出流
     * 
     * @param bufferedImage
     * @param outputStream
     * @param suffix 文件类型(后缀)
     * @throws IOException
     */
    public static void write(BufferedImage bufferedImage, OutputStream outputStream, String suffix) throws IOException {
        ImageIO.write(bufferedImage, suffix, outputStream);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(String filePath) throws Exception {
        return LONG_FILE_SYSTEM.upload(filePath);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(String fileName, String filePath) throws Exception {
        return LONG_FILE_SYSTEM.uploading(fileName, filePath);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingBySuffixToLongFileSystem(String fileSuffix, String filePath) throws Exception {
        return LONG_FILE_SYSTEM.uploadingBySuffix(fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(String bucketName, String filePath) throws Exception {
        return LONG_FILE_SYSTEM.upload(bucketName, filePath);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(String bucketName, String fileSuffix, String filePath)
        throws Exception {
        return LONG_FILE_SYSTEM.uploading(bucketName, fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到远程文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(String bucketName, String fileName, String filePath) throws Exception {
        return LONG_FILE_SYSTEM.upload(bucketName, fileName, filePath);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(byte[] bytes, String fileSuffix) throws Exception {
        return LONG_FILE_SYSTEM.uploading(bytes, fileSuffix);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(byte[] bytes, String fileName) throws Exception {
        return LONG_FILE_SYSTEM.upload(bytes, fileName);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(byte[] bytes, String fileSuffix, String bucketName)
        throws Exception {
        return LONG_FILE_SYSTEM.uploading(bytes, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(byte[] bytes, String fileName, String bucketName) throws Exception {
        return LONG_FILE_SYSTEM.upload(bytes, fileName, bucketName);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(InputStream inputStream, String fileSuffix) throws Exception {
        return LONG_FILE_SYSTEM.uploading(inputStream, fileSuffix);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(InputStream inputStream, String fileName) throws Exception {
        return LONG_FILE_SYSTEM.upload(inputStream, fileName);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToLongFileSystem(InputStream inputStream, String fileSuffix, String bucketName)
        throws Exception {
        return LONG_FILE_SYSTEM.uploading(inputStream, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到远程文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToLongFileSystem(InputStream inputStream, String fileName, String bucketName)
        throws Exception {
        return LONG_FILE_SYSTEM.upload(inputStream, fileName, bucketName);
    }

    /**
    * 从远程文件存储系统删除文件
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByLongFileSystem(String key) throws Exception {
        return LONG_FILE_SYSTEM.remove(key);
    }

    /**
    * 从远程文件存储系统删除文件
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByLongFileSystem(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.remove(bucketName, key);
    }

    /**
    * 从远程文件存储系统下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadByLongFileSystem(String key) throws Exception {
        return LONG_FILE_SYSTEM.download(key);
    }

    /**
    * 从远程文件存储系统下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadingByLongFileSystem(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.downloading(bucketName, key);
    }

    /**
    * 从远程文件存储系统下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByLongFileSystem(String key, String targetPath) throws Exception {
        return LONG_FILE_SYSTEM.download(key, targetPath);
    }

    /**
    * 从远程文件存储系统下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByLongFileSystem(String bucketName, String key, String targetPath) throws Exception {
        return LONG_FILE_SYSTEM.download(bucketName, key, targetPath);
    }

    /**
    * 根据Key从远程文件存储系统获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByLongFileSystem(String key) throws Exception {
        return LONG_FILE_SYSTEM.downloadGetBytes(key);
    }

    /**
    * 根据Key从远程文件存储系统获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByLongFileSystem(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.downloadGetBytes(bucketName, key);
    }

    /**
    * 根据Key从远程文件存储系统获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByLongFileSystem(String key) throws Exception {
        return LONG_FILE_SYSTEM.downloadGetInputStream(key);
    }

    /**
    * 根据Key从远程文件存储系统获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByLongFileSystem(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.downloadGetInputStream(bucketName, key);
    }

    /**
    * 根据Key获取远程文件存储系统Url
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrl(String key) throws Exception {
        return LONG_FILE_SYSTEM.getUrl(key);
    }

    /**
    * 根据Key获取远程文件存储系统Url
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrl(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.getUrl(bucketName, key);
    }

    /**
    * 根据Key获取远程文件存储系统Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrlTemporary(String key) throws Exception {
        return LONG_FILE_SYSTEM.getUrlTemporary(key);
    }

    /**
    * 根据Key获取远程文件存储系统Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrlTemporary(String key, long timeout) throws Exception {
        return LONG_FILE_SYSTEM.getUrlTemporary(key, timeout);
    }

    /**
    * 根据Key获取远程文件存储系统Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrlTemporary(String bucketName, String key) throws Exception {
        return LONG_FILE_SYSTEM.getUrlTemporary(bucketName, key);
    }

    /**
    * 根据Key获取远程文件存储系统Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getLongFileSystemUrlTemporary(String bucketName, String key, long timeout) throws Exception {
        return LONG_FILE_SYSTEM.getUrlTemporary(bucketName, key, timeout);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(String filePath) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(filePath);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(String fileName, String filePath) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(fileName, filePath);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingBySuffixToThisLocalityFileSystem(String fileSuffix, String filePath)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploadingBySuffix(fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(String bucketName, String filePath) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(bucketName, filePath);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(String bucketName, String fileSuffix, String filePath)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(bucketName, fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到本地文件存储系统
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(String bucketName, String fileName, String filePath)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(bucketName, fileName, filePath);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(byte[] bytes, String fileSuffix) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(bytes, fileSuffix);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(byte[] bytes, String fileName) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(bytes, fileName);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(byte[] bytes, String fileSuffix, String bucketName)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(bytes, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(byte[] bytes, String fileName, String bucketName)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(bytes, fileName, bucketName);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(InputStream inputStream, String fileSuffix)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(inputStream, fileSuffix);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(InputStream inputStream, String fileName) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(inputStream, fileName);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityFileSystem(InputStream inputStream, String fileSuffix,
        String bucketName) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.uploading(inputStream, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到本地文件存储系统
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityFileSystem(InputStream inputStream, String fileName, String bucketName)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.upload(inputStream, fileName, bucketName);
    }

    /**
    * 从本地文件存储系统删除文件
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByThisLocalityFileSystem(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.remove(key);
    }

    /**
    * 从本地文件存储系统删除文件
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByThisLocalityFileSystem(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.remove(bucketName, key);
    }

    /**
    * 从本地文件存储系统下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityFileSystem(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.download(key);
    }

    /**
    * 从本地文件存储系统下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadingByThisLocalityFileSystem(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.downloading(bucketName, key);
    }

    /**
    * 从本地文件存储系统下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityFileSystem(String key, String targetPath) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.download(key, targetPath);
    }

    /**
    * 从本地文件存储系统下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityFileSystem(String bucketName, String key, String targetPath)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.download(bucketName, key, targetPath);
    }

    /**
    * 根据Key从本地文件存储系统获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByThisLocalityFileSystem(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.downloadGetBytes(key);
    }

    /**
    * 根据Key从本地文件存储系统获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByThisLocalityFileSystem(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.downloadGetBytes(bucketName, key);
    }

    /**
    * 根据Key从本地文件存储系统获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByThisLocalityFileSystem(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.downloadGetInputStream(key);
    }

    /**
    * 根据Key从本地文件存储系统获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByThisLocalityFileSystem(String bucketName, String key)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.downloadGetInputStream(bucketName, key);
    }

    /**
    * 根据Key获取本地文件存储系统Url
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrl(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrl(key);
    }

    /**
    * 根据Key获取本地文件存储系统Url
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrl(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrl(bucketName, key);
    }

    /**
    * 根据Key获取本地文件存储系统Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrlTemporary(String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrlTemporary(key);
    }

    /**
    * 根据Key获取本地文件存储系统Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrlTemporary(String key, long timeout) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrlTemporary(key, timeout);
    }

    /**
    * 根据Key获取本地文件存储系统Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrlTemporary(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrlTemporary(bucketName, key);
    }

    /**
    * 根据Key获取本地文件存储系统Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityFileSystemUrlTemporary(String bucketName, String key, long timeout)
        throws Exception {
        return THIS_LOCALITY_FILE_SYSTEM.getUrlTemporary(bucketName, key, timeout);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(String filePath) throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(filePath);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(String fileName, String filePath) throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(fileName, filePath);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingBySuffixToThisLocalityDirectory(String fileSuffix, String filePath) throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploadingBySuffix(fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(String bucketName, String filePath) throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(bucketName, filePath);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileSuffix 文件后缀
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(String bucketName, String fileSuffix, String filePath)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(bucketName, fileSuffix, filePath);
    }

    /**
    * 将本地文件上传到本地目录
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param fileName 文件名
    * @param filePath 本地文件路径
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(String bucketName, String fileName, String filePath)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(bucketName, fileName, filePath);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(byte[] bytes, String fileSuffix) throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(bytes, fileSuffix);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(byte[] bytes, String fileName) throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(bytes, fileName);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param bytes 文件的字节流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(byte[] bytes, String fileSuffix, String bucketName)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(bytes, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param bytes 文件的字节流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(byte[] bytes, String fileName, String bucketName)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(bytes, fileName, bucketName);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(InputStream inputStream, String fileSuffix) throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(inputStream, fileSuffix);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(InputStream inputStream, String fileName) throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(inputStream, fileName);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param inputStream 文件的输入流
    * @param fileSuffix 文件后缀
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadingToThisLocalityDirectory(InputStream inputStream, String fileSuffix, String bucketName)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.uploading(inputStream, fileSuffix, bucketName);
    }

    /**
    * 将文件流上传到本地目录
    *
    * @param inputStream 文件的输入流
    * @param fileName 文件名
    * @param bucketName 服务器文件路径(一级目录)
    * @return
    * @throws Exception
    */
    public static String uploadToThisLocalityDirectory(InputStream inputStream, String fileName, String bucketName)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.upload(inputStream, fileName, bucketName);
    }

    /**
    * 从本地目录删除文件
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByThisLocalityDirectory(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.remove(key);
    }

    /**
    * 从本地目录删除文件
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 成功还是失败(true:成功,false:失败)
    * @throws Exception
    */
    public static boolean removeByThisLocalityDirectory(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.remove(bucketName, key);
    }

    /**
    * 从本地目录下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityDirectory(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.download(key);
    }

    /**
    * 从本地目录下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return
    * @throws Exception
    */
    public static boolean downloadingByThisLocalityDirectory(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.downloading(bucketName, key);
    }

    /**
    * 从本地目录下载文件到本地
    *
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityDirectory(String key, String targetPath) throws Exception {
        return THIS_LOCALITY_DIRECTORY.download(key, targetPath);
    }

    /**
    * 从本地目录下载文件到本地
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param targetPath 本地文件路径
    * @return
    * @throws Exception
    */
    public static boolean downloadByThisLocalityDirectory(String bucketName, String key, String targetPath)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.download(bucketName, key, targetPath);
    }

    /**
    * 根据Key从本地目录获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByThisLocalityDirectory(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.downloadGetBytes(key);
    }

    /**
    * 根据Key从本地目录获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static byte[] downloadGetBytesByThisLocalityDirectory(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.downloadGetBytes(bucketName, key);
    }

    /**
    * 根据Key从本地目录获取文件流
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByThisLocalityDirectory(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.downloadGetInputStream(key);
    }

    /**
    * 根据Key从本地目录获取文件流
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 文件字节流
    * @throws Exception
    */
    public static InputStream downloadGetInputStreamByThisLocalityDirectory(String bucketName, String key)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.downloadGetInputStream(bucketName, key);
    }

    /**
    * 根据Key获取本地目录Url
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrl(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrl(key);
    }

    /**
    * 根据Key获取本地目录Url
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrl(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrl(bucketName, key);
    }

    /**
    * 根据Key获取本地目录Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrlTemporary(String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrlTemporary(key);
    }

    /**
    * 根据Key获取本地目录Url(临时路径)
    *
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrlTemporary(String key, long timeout) throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrlTemporary(key, timeout);
    }

    /**
    * 根据Key获取本地目录Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrlTemporary(String bucketName, String key) throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrlTemporary(bucketName, key);
    }

    /**
    * 根据Key获取本地目录Url(临时路径)
    *
    * @param bucketName 服务器文件路径(一级目录)
    * @param key 密钥(上传后返回的字符串)
    * @param timeout 地址超时时间(单位: 毫秒)
    * @return 得到的Url
    * @throws Exception
    */
    public static String getThisLocalityDirectoryUrlTemporary(String bucketName, String key, long timeout)
        throws Exception {
        return THIS_LOCALITY_DIRECTORY.getUrlTemporary(bucketName, key, timeout);
    }

    /**
     * 关闭字节输入流
     * 
     * @param inputStream 需要关闭的字节输入流
     * @throws IOException
     */
    public static void closeStream(InputStream inputStream) throws IOException {
        if (StringUtil.isNotBlankObject(inputStream)) {
            inputStream.close();
        }
    }

    /**
     * 关闭字节输入流
     * 
     * @param inputStream 需要关闭的字节输入流
     * @throws IOException
     */
    public static void closeStream(InputStream... inputStreams) throws IOException {
        for (InputStream inputStream : inputStreams) {
            if (StringUtil.isNotBlankObject(inputStream)) {
                inputStream.close();
            }
        }
    }

    /**
     * 关闭字节输出流
     * 
     * @param outputStream 需要关闭的字节输出流
     * @throws IOException
     */
    public static void closeStream(OutputStream outputStream) throws IOException {
        if (StringUtil.isNotBlankObject(outputStream)) {
            outputStream.close();
        }
    }

    /**
     * 关闭字节输出流
     * 
     * @param outputStream 需要关闭的字节输出流
     * @throws IOException
     */
    public static void closeStream(OutputStream... outputStreams) throws IOException {
        for (OutputStream outputStream : outputStreams) {
            if (StringUtil.isNotBlankObject(outputStream)) {
                outputStream.close();
            }
        }
    }

    /**
     * 关闭字符输入流
     * 
     * @param reader 需要关闭的字符输入流
     * @throws IOException
     */
    public static void closeStream(Reader reader) throws IOException {
        if (StringUtil.isNotBlankObject(reader)) {
            reader.close();
        }
    }

    /**
     * 关闭字符输入流
     * 
     * @param reader 需要关闭的字符输入流
     * @throws IOException
     */
    public static void closeStream(Reader... readers) throws IOException {
        for (Reader reader : readers) {
            if (StringUtil.isNotBlankObject(reader)) {
                reader.close();
            }
        }
    }

    /**
     * 关闭字符输出流
     * 
     * @param reader 需要关闭的字符输出流
     * @throws IOException
     */
    public static void closeStream(Writer writer) throws IOException {
        if (StringUtil.isNotBlankObject(writer)) {
            writer.close();
        }
    }

    /**
     * 关闭字符输出流
     * 
     * @param reader 需要关闭的字符输出流
     * @throws IOException
     */
    public static void closeStream(Writer... writers) throws IOException {
        for (Writer writer : writers) {
            if (StringUtil.isNotBlankObject(writer)) {
                writer.close();
            }
        }
    }

    /**
     * 关闭字节输入输出流
     * 
     * @param inputStream 需要关闭的字节输入流
     * @param outputStream 需要关闭的字节输出流
     * @throws IOException
     */
    public static void closeStream(InputStream inputStream, OutputStream outputStream) throws IOException {
        if (StringUtil.isNotBlankObject(inputStream)) {
            inputStream.close();
        }
        if (StringUtil.isNotBlankObject(outputStream)) {
            outputStream.close();
        }
    }

    /**
     * 关闭字符输入输出流
     * 
     * @param inputStream 需要关闭的字符输入流
     * @param outputStream 需要关闭的字符输出流
     * @throws IOException
     */
    public static void closeStream(Reader reader, Writer writer) throws IOException {
        if (StringUtil.isNotBlankObject(reader)) {
            reader.close();
        }
        if (StringUtil.isNotBlankObject(writer)) {
            writer.close();
        }
    }

    /**
     * 判断一个对象是否不是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isNotBlankObject(Object obj) {
        return StringUtil.isNotBlankObject(obj);
    }

    /**
     * 格式化路径
     * 
     * @param filePath
     * @return
     */
    private static String formatUrl(String filePath) {
        return UrlUtil.format(filePath);
    }

    /**
     * 添加开头的斜线
     * 
     * @param filePath
     * @return
     */
    private static String addStartXVerify(String filePath) {
        return UrlUtil.addStartXVerify(filePath);
    }

    /**
     * 删除开头的斜线
     * 
     * @param filePath
     * @return
     */
    private static String removeStartX(String filePath) {
        return filePath = UrlUtil.removeStartX(filePath);
    }

    /**
     * 删除开头的斜线(去除前先验证)
     * 
     * @param filePath
     * @return
     */
    private static String removeStartXVerify(String filePath) {
        return filePath = UrlUtil.removeStartXVerify(filePath);
    }

}